/*
 * @Description: RT-Thread 串口底层硬件实现，后续需区分接收超时和DMA传输完成
 * @Author: Dryad
 * @Date: 2019-05-24 08:49:31
 */

#include <stm32f4xx_usart.h>
#include <stm32f4xx_dma.h>
#include <stm32f4xx_gpio.h>
#include <rtdevice.h>
#include <rthw.h>
#include <misc.h>

/*
串口
查询发送    使用TC标志
查询接收    使用RXNE标志
中断发送    使用TC标志
中断接收    使用RXNE标志
DMA发送     使用TC标志
DMA接收     使用IDLE标志和DMA传输完成中断
*/

#ifdef RT_SERIAL_USING_DMA
/* 串口DMA结构体定义 */
struct stm32_uart_dma_t
{
    DMA_Stream_TypeDef *dma_stream;
    uint32_t dma_ch;
    uint32_t dma_flag;           /* DMA中断标志 */
    IRQn_Type dma_irq_ch;        /* DMA中断号 */
    rt_size_t setting_trans_len; /* 传输数据长度 */
    rt_size_t last_trans_index;  /* 最后一次接收数据的下标 */
};
#endif // RT_SERIAL_USING_DMA

#ifdef USING_485_Pin
/* RS485方向引脚 */
struct stm32_rs485_dir_t
{
    GPIO_TypeDef *gpio;
    uint16_t pin;
};
__STATIC_INLINE void GPIO_Set(struct stm32_rs485_dir_t *dir);
__STATIC_INLINE void GPIO_Clear(struct stm32_rs485_dir_t *dir);

void GPIO_Set(struct stm32_rs485_dir_t *dir)
{
    dir->gpio->BSRRL = dir->pin;
}

void GPIO_Clear(struct stm32_rs485_dir_t *dir)
{
    dir->gpio->BSRRH = dir->pin;
}
#endif

/* Uart结构体定义 */
struct stm32_uart_t
{
    USART_TypeDef *uart_device;
    IRQn_Type irq;
#ifdef USING_485_Pin
    struct stm32_rs485_dir_t *rs485_dir;
#endif
#ifdef RT_SERIAL_USING_DMA
    struct stm32_uart_dma_t *tx_dma;
    struct stm32_uart_dma_t *rx_dma;
#endif
};

static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg);
static rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg);
static int stm32_putc(struct rt_serial_device *serial, char c);
static int stm32_getc(struct rt_serial_device *serial);
#ifdef RT_SERIAL_USING_DMA
static rt_size_t stm32_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction);
#endif

/* RT-Thread 串口驱动函数 */
static const struct rt_uart_ops stm32_uart_ops = {
    .configure = stm32_configure,
    .control = stm32_control,
    .putc = stm32_putc,
    .getc = stm32_getc,
    .dma_transmit = stm32_dma_transmit,
};

static void uart_isr(struct rt_serial_device *serial); /* 串口中断回调函数 */
#ifdef RT_SERIAL_USING_DMA
static void uart_rx_dma_configure(struct rt_serial_device *serial); /* 配置接收DMA */
static void uart_tx_dma_configure(struct rt_serial_device *serial); /* 配置发送DMA */
static void dma_uart_rx_idle_isr(struct rt_serial_device *serial);  /* DMA接收时，串口空闲中断调用函数，计算接收数据长度 */
static void dma_rx_done_isr(struct rt_serial_device *serial);       /* DMA接收完成中断 */
#endif

static void uart_nvic_configure(struct stm32_uart_t *uart, uint8_t priority, uint8_t subpriority); /*配置串口中断函数优先级*/
static void uart_gpio_init(void);                                                                  /*初始化串口IO口*/
#ifdef USING_485_Pin
static void uart_rs485_dir_init(struct stm32_uart_t *uart); /*初始化RS485方向引脚*/
#endif

#if defined(RT_USING_UART1)
/* UART1 device driver structure */

#ifdef RT_SERIAL_USING_DMA
static struct stm32_uart_dma_t uart1_tx_dma = {
    .dma_stream = DMA2_Stream7,
    .dma_ch = DMA_Channel_4,
    .dma_flag = DMA_FLAG_TCIF7,
    .dma_irq_ch = DMA2_Stream7_IRQn,
};

static struct stm32_uart_dma_t uart1_rx_dma = {
    .dma_stream = DMA2_Stream5,
    .dma_ch = DMA_Channel_4,
    .dma_flag = DMA_FLAG_TCIF5,
    .dma_irq_ch = DMA2_Stream5_IRQn,
};
#endif // RT_SERIAL_USING_DMA

static struct stm32_uart_t uart1 = {
    .uart_device = USART1,
    .irq = USART1_IRQn,
#ifdef USING_485_Pin
    .rs485_dir = RT_NULL,
#endif
#ifdef RT_SERIAL_USING_DMA
    .tx_dma = &uart1_tx_dma,
    .rx_dma = &uart1_rx_dma,
#endif
};
struct rt_serial_device serial1;

void USART1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial1);

    /* leave interrupt */
    rt_interrupt_leave();
}
#ifdef RT_SERIAL_USING_DMA
void DMA2_Stream5_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    dma_rx_done_isr(&serial1);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif // RT_SERIAL_USING_DMA
#endif /* RT_USING_UART1 */

#if defined(RT_USING_UART2)
/* UART2 device driver structure */
#ifdef RT_SERIAL_USING_DMA
static struct stm32_uart_dma_t uart2_tx_dma = {
    .dma_stream = DMA1_Stream6,
    .dma_ch = DMA_Channel_4,
    .dma_flag = DMA_FLAG_TCIF6,
    .dma_irq_ch = DMA1_Stream6_IRQn,
};
#endif // RT_SERIAL_USING_DMA

static struct stm32_uart_t uart2 = {
    .uart_device = USART2,
    .irq = USART2_IRQn,
#ifdef USING_485_Pin
    .rs485_dir = RT_NULL,
#endif
#ifdef RT_SERIAL_USING_DMA
    .tx_dma = &uart2_tx_dma,
    .rx_dma = RT_NULL,
#endif // RT_SERIAL_USING_DMA
};
static struct rt_serial_device serial2;

void USART2_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial2);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif /* RT_USING_UART2 */

#if defined(RT_USING_UART3)
/* UART3 device driver structure */
#ifdef RT_SERIAL_USING_DMA
static struct stm32_uart_dma_t uart3_rx_dma = {
    .dma_stream = DMA1_Stream1,
    .dma_ch = DMA_Channel_4,
    .dma_flag = DMA_FLAG_TCIF1,
    .dma_irq_ch = DMA1_Stream1_IRQn,
};
#endif // RT_SERIAL_USING_DMA

static struct stm32_uart_t uart3 = {
    .uart_device = USART3,
    .irq = USART3_IRQn,
#ifdef USING_485_Pin
    .rs485_dir = RT_NULL,
#endif
#ifdef RT_SERIAL_USING_DMA
    .tx_dma = RT_NULL,
    .rx_dma = &uart3_rx_dma,
#endif // RT_SERIAL_USING_DMA
};

struct rt_serial_device serial3;

void USART3_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial3);

    /* leave interrupt */
    rt_interrupt_leave();
}

#ifdef RT_SERIAL_USING_DMA
void DMA1_Stream1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    dma_rx_done_isr(&serial3);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif // RT_SERIAL_USING_DMA
#endif /* RT_USING_UART3 */

#if defined(RT_USING_UART4)
/* UART4 device driver structure */

static struct stm32_uart_t uart4 = {
    .uart_device = UART4,
    .irq = UART4_IRQn,
#ifdef USING_485_Pin
    .rs485_dir = RT_NULL,
#endif
#ifdef RT_SERIAL_USING_DMA
    .tx_dma = RT_NULL,
    .rx_dma = RT_NULL,
#endif // RT_SERIAL_USING_DMA
};
struct rt_serial_device serial4;

void UART4_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial4);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif /* RT_USING_UART4 */

#if defined(RT_USING_UART5)
/* UART5 device driver structure */
#ifdef RT_SERIAL_USING_DMA
static struct stm32_uart_dma_t uart5_rx_dma = {
    .dma_stream = DMA1_Stream0,
    .dma_ch = DMA_Channel_4,
    .dma_flag = DMA_FLAG_TCIF0,
    .dma_irq_ch = DMA1_Stream0_IRQn,
};
#endif // RT_SERIAL_USING_DMA

#ifdef USING_485_Pin
struct stm32_rs485_dir_t uart5_rs485_dir = {
    .gpio = GPIOD,
    .pin = GPIO_Pin_0,
};
#endif

struct stm32_uart_t uart5 = {
    .uart_device = UART5,
    .irq = UART5_IRQn,
#ifdef USING_485_Pin
    .rs485_dir = &uart5_rs485_dir,
#endif
#ifdef RT_SERIAL_USING_DMA
    .tx_dma = RT_NULL,
    .rx_dma = &uart5_rx_dma,
#endif // RT_SERIAL_USING_DMA
};
struct rt_serial_device serial5;

void UART5_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial5);

    /* leave interrupt */
    rt_interrupt_leave();
}

#ifdef RT_SERIAL_USING_DMA
void DMA1_Stream0_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    dma_rx_done_isr(&serial5);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif // RT_SERIAL_USING_DMA
#endif /* RT_USING_UART5 */

#if defined(RT_USING_UART6)
/* UART4 device driver structure */
#ifdef RT_SERIAL_USING_DMA
static struct stm32_uart_dma_t uart6_tx_dma = {
    .dma_stream = DMA2_Stream6,
    .dma_ch = DMA_Channel_5,
    .dma_flag = DMA_FLAG_TCIF6,
    .dma_irq_ch = DMA2_Stream6_IRQn,
};

static struct stm32_uart_dma_t uart6_rx_dma = {
    .dma_stream = DMA2_Stream1,
    .dma_ch = DMA_Channel_5,
    .dma_flag = DMA_FLAG_TCIF1,
    .dma_irq_ch = DMA2_Stream1_IRQn,
};
#endif // RT_SERIAL_USING_DMA

static struct stm32_uart_t uart6 = {
    .uart_device = USART6,
    .irq = USART6_IRQn,
#ifdef USING_485_Pin
    .rs485_dir = RT_NULL,
#endif
#ifdef RT_SERIAL_USING_DMA
    .tx_dma = &uart6_tx_dma,
    .rx_dma = &uart6_rx_dma,
#endif // RT_SERIAL_USING_DMA
};
struct rt_serial_device serial6;

void USART6_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    uart_isr(&serial6);

    /* leave interrupt */
    rt_interrupt_leave();
}

#ifdef RT_SERIAL_USING_DMA
void DMA2_Stream1_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    dma_rx_done_isr(&serial6);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif
#endif /* RT_USING_UART6 */

rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
{
    struct stm32_uart_t *uart;
    USART_InitTypeDef USART_InitStructure;

    RT_ASSERT(serial != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

    uart = (struct stm32_uart_t *)serial->parent.user_data;

    USART_InitStructure.USART_BaudRate = cfg->baud_rate;

    if (cfg->data_bits == DATA_BITS_8)
    {
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    }
    else if (cfg->data_bits == DATA_BITS_9)
    {
        USART_InitStructure.USART_WordLength = USART_WordLength_9b;
    }

    if (cfg->stop_bits == STOP_BITS_1)
    {
        USART_InitStructure.USART_StopBits = USART_StopBits_1;
    }
    else if (cfg->stop_bits == STOP_BITS_2)
    {
        USART_InitStructure.USART_StopBits = USART_StopBits_2;
    }

    if (cfg->parity == PARITY_NONE)
    {
        USART_InitStructure.USART_Parity = USART_Parity_No;
    }
    else if (cfg->parity == PARITY_ODD)
    {
        USART_InitStructure.USART_Parity = USART_Parity_Odd;
    }
    else if (cfg->parity == PARITY_EVEN)
    {
        USART_InitStructure.USART_Parity = USART_Parity_Even;
    }

    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(uart->uart_device, &USART_InitStructure);

    /* Enable USART */
    USART_Cmd(uart->uart_device, ENABLE);

    return RT_EOK;
}

rt_err_t stm32_control(struct rt_serial_device *serial, int cmd, void *arg)
{
    struct stm32_uart_t *uart;
    rt_uint32_t ctrl_arg = (rt_uint32_t)(arg);

    RT_ASSERT(serial != RT_NULL);
    uart = (struct stm32_uart_t *)serial->parent.user_data;

    switch (cmd)
    {
    case RT_DEVICE_CTRL_CLR_INT: /* 清除中断 */
    {
        NVIC_DisableIRQ(uart->irq); /* 关闭串口中断 */
#ifdef RT_SERIAL_USING_DMA
        NVIC_DisableIRQ(uart->rx_dma->dma_irq_ch); /* 关闭接收DMA传输完成中断 */
#endif
        switch (ctrl_arg)
        {
        case RT_DEVICE_FLAG_INT_RX:
            USART_ITConfig(uart->uart_device, USART_IT_RXNE, DISABLE);
            break;
        case RT_DEVICE_FLAG_INT_TX:
            USART_ITConfig(uart->uart_device, USART_IT_TC, DISABLE);
            break;
#ifdef RT_SERIAL_USING_DMA
        case RT_DEVICE_FLAG_DMA_RX:
            DMA_ITConfig(uart->rx_dma->dma_stream, DMA_IT_TC, DISABLE);
            USART_ITConfig(uart->uart_device, USART_IT_IDLE, DISABLE);
            break;
        case RT_DEVICE_FLAG_DMA_TX:
            USART_ITConfig(uart->uart_device, USART_IT_TC, DISABLE);
            break;
#endif // RT_SERIAL_USING_DMA
        }
    }
    break;
    case RT_DEVICE_CTRL_SET_INT: /* 设置中断 */
    {
        switch (ctrl_arg)
        {
        case RT_DEVICE_FLAG_INT_RX:
            USART_ITConfig(uart->uart_device, USART_IT_RXNE, ENABLE);
            break;
        case RT_DEVICE_FLAG_INT_TX:
            USART_ITConfig(uart->uart_device, USART_IT_TC, ENABLE);
            break;
#ifdef RT_SERIAL_USING_DMA
        case RT_DEVICE_FLAG_DMA_RX:
            DMA_ITConfig(uart->rx_dma->dma_stream, DMA_IT_TC, ENABLE);
            USART_ITConfig(uart->uart_device, USART_IT_IDLE, ENABLE);
            NVIC_EnableIRQ(uart->rx_dma->dma_irq_ch); /* 打开接收DMA传输完成中断 */
            break;
        case RT_DEVICE_FLAG_DMA_TX:
            USART_ITConfig(uart->uart_device, USART_IT_TC, ENABLE);
            break;
#endif // RT_SERIAL_USING_DMA
        }
        NVIC_EnableIRQ(uart->irq); /* 打开串口中断 */
    }
    break;
#ifdef RT_SERIAL_USING_DMA
    case RT_DEVICE_CTRL_CONFIG:
    {
        switch (ctrl_arg)
        {
        case RT_DEVICE_FLAG_DMA_RX:
            uart_rx_dma_configure(serial);                            /* 配置接收用DMA */
            USART_ITConfig(uart->uart_device, USART_IT_IDLE, ENABLE); /* 打开串口空闲中断 */
            break;
        case RT_DEVICE_FLAG_DMA_TX:
            uart_tx_dma_configure(serial);                          /* 配置发送用DMA */
            USART_ITConfig(uart->uart_device, USART_IT_TC, ENABLE); /* 打开串口发送完成中断 */
            break;
        }
        NVIC_EnableIRQ(uart->irq);
    }
    break;
#endif // RT_SERIAL_USING_DMA
    }

    return RT_EOK;
}

int stm32_putc(struct rt_serial_device *serial, char c)
{
    struct stm32_uart_t *uart;

    RT_ASSERT(serial != RT_NULL);
    uart = (struct stm32_uart_t *)serial->parent.user_data;

    /*中断发送*/
    if (serial->parent.open_flag & RT_DEVICE_FLAG_INT_TX)
    {
        if (!(uart->uart_device->SR & USART_FLAG_TXE))
        {
            /* 传输未完成 */
            return -1;
        }
#ifdef USING_485_Pin
        if (uart->rs485_dir != RT_NULL)
        {
            /* 设置485引脚为发送 */
            GPIO_Set(uart->rs485_dir);
        }
#endif
        /* 发送一个字节 */
        uart->uart_device->DR = c;
    }
    /*查询发送*/
    else
    {
        USART_ClearFlag(uart->uart_device, USART_FLAG_TC);
#ifdef USING_485_Pin
        if (uart->rs485_dir != RT_NULL)
        {
            /* 设置485引脚为发送 */
            GPIO_Set(uart->rs485_dir);
        }
#endif

        uart->uart_device->DR = c;

        while (!((uart->uart_device->SR) & USART_FLAG_TC))
            ; /* 等待传输完成 */
#ifdef USING_485_Pin
        if (uart->rs485_dir != RT_NULL)
        {
            /* 设置485引脚为接收 */
            GPIO_Clear(uart->rs485_dir);
        }
#endif
    }

    return 1;
}

int stm32_getc(struct rt_serial_device *serial)
{
    int ch;
    struct stm32_uart_t *uart;

    RT_ASSERT(serial != RT_NULL);
    uart = (struct stm32_uart_t *)serial->parent.user_data;

    ch = -1;
    if (uart->uart_device->SR & USART_FLAG_RXNE)
    {
        ch = uart->uart_device->DR & 0xff;
    }

    return ch;
}

#ifdef RT_SERIAL_USING_DMA
rt_size_t stm32_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
{
    /*发送*/
    if (direction == RT_SERIAL_DMA_TX)
    {
        /*
		* 在stm32f4的手册中，DMA-SR寄存器说明下面有一句话
		* 将 EN 位置“1”以启动新传输之前， DMA_LISR 或 DMA_HISR 寄存器中与数据流相对应的事件标志必须清零
		*
		* 在传输结束前禁止数据流（EN位清零），会产生传输完成事件
		*/

        uint8_t x = 0;         //指示当前是哪个流，DMAy_Streamx
        uint32_t add_temp = 0; //保存需修改寄存器的地址
        uint32_t temp = 0;

        struct stm32_uart_t *uart = (struct stm32_uart_t *)serial->parent.user_data;

        RT_ASSERT(uart != RT_NULL);

        DMA_Stream_TypeDef *dma_stream = uart->tx_dma->dma_stream;

        dma_stream->CR &= ~DMA_SxCR_EN;
        if (dma_stream < DMA2_Stream0)
        {
            x = ((uint32_t)dma_stream - (uint32_t)DMA1_Stream0) / 0x18; //获取当前流控制器
            add_temp = (uint32_t) & (DMA1->LIFCR) + (x & (0x04));       //保存寄存器地址
        }
        else
        {
            x = ((uint32_t)dma_stream - (uint32_t)DMA2_Stream0) / 0x18;
            add_temp = (uint32_t) & (DMA2->LIFCR) + (x & (0x04)); //保存寄存器地址
        }
        temp = (0x3D << (6 * (x & 0x01))) << ((x & 0x02) << 3);
        *(uint32_t *)add_temp = temp; //清除所有中断标志

        dma_stream->M0AR = (uint32_t)buf;
        dma_stream->NDTR = size;
        dma_stream->CR |= DMA_SxCR_EN;
        return size;
    }
    return 0;
}
#endif // RT_SERIAL_USING_DMA

/*
中断发送    使用TC标志
中断接收    使用RXNE标志
DMA发送     使用TC标志
DMA接收     使用IDLE标志
*/
/**
 * @description: 串口中断服务函数
 * @param {type} 
 * @return: void
 */
void uart_isr(struct rt_serial_device *serial)
{
    struct stm32_uart_t *uart = (struct stm32_uart_t *)serial->parent.user_data;

    RT_ASSERT(uart != RT_NULL);

    /*读取SR寄存器*/
    uint16_t SR_value = uart->uart_device->SR;
    const uint16_t CR1_value = uart->uart_device->CR1;
    /* RXNE中断使能且触发中断，中断接收 */
    if ((CR1_value & (1 << 5)) && (SR_value & (1 << 5)))
    {
        /* 读数据的软件序列也能清除RXNE标志 */
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
    }

    /*IDLE中断使能且触发，DMA接收*/
    if ((CR1_value & (1 << 4)) && (SR_value & (1 << 4)))
    {
#ifdef RT_SERIAL_USING_DMA
        /*先执行接收回调函数，再清除IDLE标志，回调函数可以根据IDLE标志判断当前是否接收完成*/
        dma_uart_rx_idle_isr(serial);
#endif
        /*清除中断标志位*/
        USART_ReceiveData(uart->uart_device);
    }

    /* TC中断使能且触发中断，DMA发送和中断发送 */
    if ((CR1_value & (1 << 6)) && (SR_value & (1 << 6)))
    {
        /*清除中断标志*/
        uart->uart_device->SR &= ~(1 << 6);
        /*设置485方向引脚为接收*/
#ifdef USING_485_Pin
        if (uart->rs485_dir != RT_NULL)
        {
            GPIO_Clear(uart->rs485_dir);
        }
#endif
#ifdef RT_SERIAL_USING_DMA
        /*中断发送*/
        if (serial->parent.open_flag & RT_DEVICE_FLAG_INT_TX)
        {
            rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
        }
        /*DMA发送*/
        else if (serial->parent.open_flag & RT_DEVICE_FLAG_DMA_TX)
        {
            rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DMADONE);
        }
#else
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DONE);
#endif // RT_SERIAL_USING_DMA
    }

    /*溢出错误*/
    if (uart->uart_device->SR & (1 << 3))
    {
        /*清除错误标志*/
        USART_ReceiveData(uart->uart_device);
    }
}

#ifdef RT_SERIAL_USING_DMA
/**
 * @description: 配置接收用DMA，打开DMA传输完成中断
 * @param {type} 
 * @return: 
 */
void uart_rx_dma_configure(struct rt_serial_device *serial)
{
    struct stm32_uart_t *uart = (struct stm32_uart_t *)serial->parent.user_data;
    struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;

    DMA_InitTypeDef DMA_InitStructure;
    /* rx dma config */
    RT_ASSERT(uart->rx_dma != RT_NULL);
    uart->rx_dma->setting_trans_len = serial->config.bufsz;
    uart->rx_dma->last_trans_index = 0;
    DMA_DeInit(uart->rx_dma->dma_stream);
    while (DMA_GetCmdStatus(uart->rx_dma->dma_stream) != DISABLE)
        ;
    DMA_InitStructure.DMA_Channel = uart->rx_dma->dma_ch;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (uart->uart_device->DR);
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)rx_fifo->buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = uart->rx_dma->setting_trans_len;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(uart->rx_dma->dma_stream, &DMA_InitStructure);

    NVIC_InitTypeDef NVIC_InitStructure;

    /* Enable the USART1 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = uart->rx_dma->dma_irq_ch;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_DMACmd(uart->uart_device, USART_DMAReq_Rx, ENABLE);
    DMA_ClearFlag(uart->rx_dma->dma_stream, uart->rx_dma->dma_flag);
    DMA_ITConfig(uart->rx_dma->dma_stream, DMA_IT_TC, ENABLE);
    DMA_Cmd(uart->rx_dma->dma_stream, ENABLE);

    NVIC_EnableIRQ(uart->rx_dma->dma_irq_ch); /* 打开接收DMA传输完成中断 */
}

void uart_tx_dma_configure(struct rt_serial_device *serial)
{
    struct stm32_uart_t *uart = (struct stm32_uart_t *)serial->parent.user_data;
    DMA_InitTypeDef DMA_InitStructure;

    RT_ASSERT(uart->tx_dma != RT_NULL);
    DMA_DeInit(uart->tx_dma->dma_stream);
    while (DMA_GetCmdStatus(uart->tx_dma->dma_stream) != DISABLE)
        ;
    DMA_InitStructure.DMA_Channel = uart->tx_dma->dma_ch;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (uart->uart_device->DR);
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0;
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_BufferSize = 0;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(uart->tx_dma->dma_stream, &DMA_InitStructure);

    USART_DMACmd(uart->uart_device, USART_DMAReq_Tx, ENABLE);
    DMA_Cmd(uart->tx_dma->dma_stream, ENABLE);
}

void dma_uart_rx_idle_isr(struct rt_serial_device *serial)
{
    struct stm32_uart_t *uart = (struct stm32_uart_t *)serial->parent.user_data;
    rt_size_t current_put_index, recv_len;
    rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    /*计算当前DMA已传输数量*/
    current_put_index = uart->rx_dma->setting_trans_len - DMA_GetCurrDataCounter(uart->rx_dma->dma_stream);
    recv_len = current_put_index - uart->rx_dma->last_trans_index;
    uart->rx_dma->last_trans_index = current_put_index;

    /* enable interrupt */
    rt_hw_interrupt_enable(level);

    if (recv_len)
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_TIMEOUT | (recv_len << 8));
}

void dma_rx_done_isr(struct rt_serial_device *serial)
{
    struct stm32_uart_t *uart = (struct stm32_uart_t *)serial->parent.user_data;
    rt_size_t recv_len;
    rt_base_t level;

    /* 传输完成中断 */
    if (DMA_GetFlagStatus(uart->rx_dma->dma_stream, uart->rx_dma->dma_flag) != RESET)
    {
        /* disable interrupt */
        level = rt_hw_interrupt_disable();

        recv_len = uart->rx_dma->setting_trans_len - uart->rx_dma->last_trans_index;
        /* reset last recv index */
        uart->rx_dma->last_trans_index = 0;
        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        if (recv_len)
            rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | (recv_len << 8));

        /* start receive data */
        DMA_ClearFlag(uart->rx_dma->dma_stream, uart->rx_dma->dma_flag);
    }
}
#endif

void uart_nvic_configure(struct stm32_uart_t *uart, uint8_t priority, uint8_t subpriority)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = uart->irq;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = priority;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = subpriority;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void uart_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;

#ifdef RT_USING_UART1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
    GPIO_Init(GPIOA, &GPIO_InitStructure);

#ifdef USING_485_Pin
    uart_rs485_dir_init(&uart1);
#endif
#endif /* RT_USING_UART1 */

#ifdef RT_USING_UART2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_USART2);
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_USART2);
    GPIO_Init(GPIOD, &GPIO_InitStructure);

#ifdef USING_485_Pin
    uart_rs485_dir_init(&uart2);
#endif
#endif /* RT_USING_UART2 */

#ifdef RT_USING_UART3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_USART3);
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_USART3);
    GPIO_Init(GPIOD, &GPIO_InitStructure);

#ifdef USING_485_Pin
    uart_rs485_dir_init(&uart3);
#endif
#endif /* RT_USING_UART3 */

#ifdef RT_USING_UART4
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_UART4);
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_UART4);
    GPIO_Init(GPIOC, &GPIO_InitStructure);

#ifdef USING_485_Pin
    uart_rs485_dir_init(&uart4);
#endif
#endif /* RT_USING_UART4 */

#ifdef RT_USING_UART5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_UART5);
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_UART5);
    GPIO_Init(GPIOD, &GPIO_InitStructure);

#ifdef USING_485_Pin
    uart_rs485_dir_init(&uart5);
#endif
#endif /* RT_USING_UART5 */

#ifdef RT_USING_UART6
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource14, GPIO_AF_USART6);
    GPIO_Init(GPIOG, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource9, GPIO_AF_USART6);
    GPIO_Init(GPIOG, &GPIO_InitStructure);
#ifdef USING_485_Pin
    uart_rs485_dir_init(&uart6);
#endif
#endif /* RT_USING_UART6 */
}

#ifdef USING_485_Pin
void uart_rs485_dir_init(struct stm32_uart_t *uart)
{
    if (uart->rs485_dir == RT_NULL)
        return;

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;

    GPIO_InitStructure.GPIO_Pin = uart->rs485_dir->pin;

    GPIO_Init(uart->rs485_dir->gpio, &GPIO_InitStructure);

    GPIO_Clear(uart->rs485_dir);
}
#endif

static int stm32_uart_register(void)
{
    struct stm32_uart_t *uart;
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;

    /* 配置GPIO口 */
    uart_gpio_init();

#ifdef RT_USING_UART1
    uart = &uart1;

    serial1.ops = &stm32_uart_ops;
    serial1.config = config;
    uart_nvic_configure(uart, 2, 1);
    /* register UART1 device */
    rt_hw_serial_register(&serial1,
                          "uart1",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX,
                          uart);
#endif /* RT_USING_UART1 */

#ifdef RT_USING_UART2
    uart = &uart2;

    serial2.ops = &stm32_uart_ops;
    serial2.config = config;
    uart_nvic_configure(uart, 2, 1);
    /* register UART1 device */
    rt_hw_serial_register(&serial2,
                          "uart2",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_DMA_TX,
                          uart);
#endif /* RT_USING_UART2 */

#ifdef RT_USING_UART3
    uart = &uart3;

    serial3.ops = &stm32_uart_ops;
    serial3.config = config;
    uart_nvic_configure(uart, 2, 1);
    /* register UART3 device */
    rt_hw_serial_register(&serial3,
                          "uart3",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_INT_TX,
                          uart);
#endif /* RT_USING_UART3 */

#ifdef RT_USING_UART4
    uart = &uart4;

    serial4.ops = &stm32_uart_ops;
    serial4.config = config;
    uart_nvic_configure(uart, 2, 1);
    /* register UART4 device */
    rt_hw_serial_register(&serial4,
                          "uart4",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX,
                          uart);
#endif /* RT_USING_UART4 */

#ifdef RT_USING_UART5
    uart = &uart5;

    serial5.ops = &stm32_uart_ops;
    serial5.config = config;
    uart_nvic_configure(uart, 2, 1);

    /* register UART5 device */
    rt_hw_serial_register(&serial5,
                          "uart5",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_DMA_RX,
                          uart);
#endif /* RT_USING_UART5 */

#ifdef RT_USING_UART6
    uart = &uart6;

    serial6.ops = &stm32_uart_ops;
    serial6.config = config;
    uart_nvic_configure(uart, 2, 1);
    /* register UART4 device */
    rt_hw_serial_register(&serial6,
                          "uart6",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_DMA_TX,
                          uart);
#endif /* RT_USING_UART6 */
    return 0;
}
INIT_BOARD_EXPORT(stm32_uart_register);
